package com.qinggeng.project.tool.file.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.qinggeng.common.constant.Constants;
import com.qinggeng.common.enums.StorageTypeEnum;
import com.qinggeng.common.exception.CustomException;
import com.qinggeng.common.utils.DateUtils;
import com.qinggeng.common.utils.IdUtils;
import com.qinggeng.common.utils.file.FileUtils;
import com.qinggeng.framework.config.ServerConfig;
import com.qinggeng.project.system.service.ISysConfigService;
import com.qinggeng.project.tool.file.domain.SysFile;
import com.qinggeng.project.tool.file.domain.json.FileConfigJson;
import com.qinggeng.project.tool.file.mapper.SysFileMapper;
import com.qinggeng.project.tool.file.service.ISysFileService;
import com.qinggeng.project.tool.file.util.QiNiuUtil;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.util.Auth;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.util.List;

/**
 * 文件存储Service业务层处理
 *
 * @author qinggeng
 * @date 2020-02-11
 */
@Service
@Slf4j
public class SysFileServiceImpl implements ISysFileService
{
    @Resource
    private SysFileMapper sysFileMapper;

    @Autowired
    private ServerConfig serverConfig;

    @Autowired
    private ISysConfigService configService;

    @Value("${qinggeng.profile}")
    private String profile;
    @Value("${qinggeng.maxSize}")
    private Long maxSize;



    @Value("${spring.profiles.active}")
    private String active;


    /**
     * 查询文件存储
     *
     * @param fileId 文件存储ID
     * @return 文件存储
     */
    @Override
    public SysFile selectSysFileById(Long fileId)
    {
        return sysFileMapper.selectSysFileById(fileId);
    }

    /**
     * 查询文件存储列表
     *
     * @param sysFile 文件存储
     * @return 文件存储
     */
    @Override
    public List<SysFile> selectSysFileList(SysFile sysFile)
    {
        return sysFileMapper.selectSysFileList(sysFile);
    }

    /**
     * 新增文件存储
     *
     * @param sysFile 文件存储
     * @return 结果
     */
    @Override
    public int insertSysFile(SysFile sysFile)
    {
        sysFile.setCreateTime(DateUtils.getNowDate());
//        /**
//         * 生产环境数据库保存图片路径时将http换成https
//         */
//        if (active.equals(Constants.TEST_ENVIRONMENT)){
//
//        }else if (active.equals(Constants.PRO_ENVIRONMENT)){
//            sysFile.setPath("https"+sysFile.getPath().substring(4));
//        }
        return sysFileMapper.insertSysFile(sysFile);
    }

    /**
     * 修改文件存储
     *
     * @param sysFile 文件存储
     * @return 结果
     */
    @Override
    public int updateSysFile(SysFile sysFile)
    {
        return sysFileMapper.updateSysFile(sysFile);
    }

    /**
     * 批量删除文件存储
     *
     * @param fileIds 需要删除的文件存储ID
     * @return 结果
     */
    @Override
    @Transactional
    public void deleteSysFileByIds(Long[] fileIds)
    {
        for (Long id :fileIds){
            SysFile sysFile = sysFileMapper.selectSysFileById(id);
            if (sysFile.getStorageType().equals(StorageTypeEnum.LOCAL.getCode())){
                deleteLocal(sysFile.getDeleteUrl(),id);
                continue;
            }
            if (sysFile.getStorageType().equals(StorageTypeEnum.QINIU.getCode())){
                deleteQiniu(sysFile.getDeleteUrl(),id);
            }
        }
    }


    /**
     * 本地删除
     * @param deleteUrl 删除地址
     * @param id ID
     */
    private void deleteLocal(String deleteUrl,Long id){
        FileUtils.del(deleteUrl);
        sysFileMapper.deleteSysFileById(id);
    }

    /**
     * 删除七牛
     * @param deleteUrl 删除地址
     * @param id ID
     */
    private void deleteQiniu(String deleteUrl,Long id){
        String fileConfigJson = configService.selectConfigByKey("sys.file.config").toString();
        FileConfigJson configObject = JSON.parseObject(fileConfigJson, FileConfigJson.class);
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(QiNiuUtil.getRegion(configObject.getZone()));
        Auth auth = Auth.create(configObject.getAccessKey(), configObject.getSecretKey());
        BucketManager bucketManager = new BucketManager(auth, cfg);
        try {
            bucketManager.delete(configObject.getBucket(), deleteUrl);
            sysFileMapper.deleteSysFileById(id);
        }catch (QiniuException e){
            sysFileMapper.deleteSysFileById(id);
        }
    }

    /**
     * 删除文件存储信息
     *
     * @param fileId 文件存储ID
     * @return 结果
     */
    @Override
    public int deleteSysFileById(Long fileId)
    {
        SysFile sysFile = sysFileMapper.selectSysFileById(fileId);
        FileUtils.del(sysFile.getDeleteUrl());
        return sysFileMapper.deleteSysFileById(fileId);
    }

    @Override
    @Transactional
    public SysFile upload(MultipartFile multipartFile,Boolean domain) {
        String fileConfigJson = configService.selectConfigByKey("sys.file.config").toString();
        FileConfigJson configObject = JSON.parseObject(fileConfigJson, FileConfigJson.class);
        if (configObject.getStorageType().equals(StorageTypeEnum.LOCAL.getCode())){
            return uploadLocal(multipartFile,domain);
        }
        if (configObject.getStorageType().equals(StorageTypeEnum.QINIU.getCode())){
            return uploadQiniu(multipartFile);
        }

        throw new CustomException("当前类型上传方式不存在请联系管理员");
    }

    @Value("${qinggeng.compressEnabled}")
    private boolean compressEnabled;

    /**
     * 上传本地
     * @param multipartFile 文件
     * @param domain 是否显示域名
     * @return /
     */
    private SysFile uploadLocal(MultipartFile multipartFile,Boolean domain){
        FileUtils.checkSize(maxSize, multipartFile.getSize());
        String suffix = FileUtils.getExtensionName(multipartFile.getOriginalFilename().replaceAll(",",""));
        String type = FileUtils.getFileType(suffix);
        File file = FileUtils.upload(multipartFile,profile + "/" + type +  File.separator);
        if(ObjectUtil.isNull(file)){
            throw new CustomException("上传失败");
        }
        try {
            if (compressEnabled){
                Thumbnails.of(profile + "/" + type +  File.separator + file.getName().replaceAll(",","")).scale(0.5f).toFile(profile + "/" + type +  File.separator + file.getName().replaceAll(",",""));
            }
            String name = FileUtils.getFileNameNoEx(multipartFile.getOriginalFilename().replaceAll(",",""));
            SysFile sysFile = new SysFile();
            sysFile.setRealName(name);
            sysFile.setName(FileUtils.getFileNameNoEx(file.getName().replaceAll(",","")));
            sysFile.setSuffix(suffix);
            sysFile.setPath(serverConfig.getUrl() + Constants.RESOURCE_PREFIX + "/" + type + "/" + file.getName().replaceAll(",",""));
            sysFile.setDeleteUrl(file.getPath().replaceAll(",",""));
            sysFile.setType(type);
            sysFile.setSize(FileUtils.getSize(multipartFile.getSize()));
            sysFile.setStorageType(StorageTypeEnum.LOCAL.getCode());
            if (!domain){
                sysFile.setPath(Constants.RESOURCE_PREFIX + "/" + type + "/" + file.getName().replaceAll(",",""));
            }
            insertSysFile(sysFile);
            return sysFile;
        }catch (Exception e){
            FileUtils.del(file);
            throw new CustomException(e.getMessage());
        }
    }
    /**
     * 上传七牛云
     * @param multipartFile 文件
     * @return /
     */
    private SysFile uploadQiniu(MultipartFile multipartFile){
        log.info("********上传七牛云*********maxSize:"+maxSize);
        FileUtils.checkSize(maxSize, multipartFile.getSize());
        String fileConfigJson = configService.selectConfigByKey("sys.file.config").toString();

        FileConfigJson configObject = JSON.parseObject(fileConfigJson, FileConfigJson.class);
        String suffix = FileUtils.getExtensionName(multipartFile.getOriginalFilename());
        String type = FileUtils.getFileType(suffix);

        // 构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(QiNiuUtil.getRegion(configObject.getZone()));
        UploadManager uploadManager = new UploadManager(cfg);
        Auth auth = Auth.create(configObject.getAccessKey(), configObject.getSecretKey());
        String upToken = auth.uploadToken(configObject.getBucket());
        try {
            //String key = multipartFile.getOriginalFilename();
            String key = IdUtils.simpleUUID() + "." + suffix;
            if(sysFileMapper.selectSysFileByName(FileUtils.getFileNameNoEx(key)) != null) {
                key = QiNiuUtil.getKey(key);
            }

            Response response = uploadManager.put(multipartFile.getBytes(), key, upToken);
            //解析上传成功的结果


            DefaultPutRet putRet = JSON.parseObject(response.bodyString(), DefaultPutRet.class);

            SysFile sysFile = new SysFile();
            sysFile.setRealName(FileUtils.getFileNameNoEx(multipartFile.getOriginalFilename()));
            sysFile.setName(FileUtils.getFileNameNoEx(key));
            sysFile.setSuffix(suffix);
            sysFile.setPath(configObject.getHost() + "/" +putRet.key);
            sysFile.setDeleteUrl(putRet.key);
            sysFile.setType(type);
            sysFile.setSize(FileUtils.getSize(multipartFile.getSize()));
            sysFile.setStorageType(StorageTypeEnum.QINIU.getCode());
            insertSysFile(sysFile);
            return sysFile;
        }catch (Exception e){
            throw new CustomException(e.getMessage());
        }
    }

    @Override
    @Transactional
    public void synchronize() {
        String fileConfigJson = configService.selectConfigByKey("sys.file.config").toString();
        FileConfigJson configObject = JSON.parseObject(fileConfigJson, FileConfigJson.class);
        if (configObject.getStorageType().equals(StorageTypeEnum.LOCAL.getCode())){
            throw new CustomException("本地上传无需同步");
        }
        //构造一个带指定Zone对象的配置类
        Configuration cfg = new Configuration(QiNiuUtil.getRegion(configObject.getZone()));
        Auth auth = Auth.create(configObject.getAccessKey(), configObject.getSecretKey());
        BucketManager bucketManager = new BucketManager(auth, cfg);
        //文件名前缀
        String prefix = "";
        //每次迭代的长度限制，最大1000，推荐值 1000
        int limit = 1000;
        //指定目录分隔符，列出所有公共前缀（模拟列出目录效果）。缺省值为空字符串
        String delimiter = "";
        //列举空间文件列表
        BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(configObject.getBucket(), prefix, limit, delimiter);
        SysFile sysFile;
        while (fileListIterator.hasNext()) {
            FileInfo[] items = fileListIterator.next();
            for (FileInfo item : items) {
                if (sysFileMapper.selectSysFileByName(FileUtils.getFileNameNoEx(item.key.substring(item.key.lastIndexOf("/") + 1))) == null){
                    sysFile = new SysFile();
                    sysFile.setRealName(FileUtils.getFileNameNoEx(item.key.substring(item.key.lastIndexOf("/") + 1)));
                    sysFile.setName(FileUtils.getFileNameNoEx(item.key.substring(item.key.lastIndexOf("/") + 1)));
                    sysFile.setSuffix(FileUtils.getExtensionName(item.key));
                    sysFile.setPath(configObject.getHost() + "/" + item.key);
                    sysFile.setDeleteUrl(item.key);
                    sysFile.setType(FileUtils.getFileType(FileUtils.getExtensionName(item.key)));
                    sysFile.setSize(FileUtils.getSize(Integer.parseInt(item.fsize+"")));
                    sysFile.setStorageType(StorageTypeEnum.QINIU.getCode());
                    insertSysFile(sysFile);
                }
            }
        }

    }

    /**
     * 根据文件路径删除文件
     * @param path
     */
    @Override
    @Transactional
    public void deleteSysFileByPath(String path) {
        try {
            SysFile sysFile = sysFileMapper.selectSysFileByPath(path);
            if (sysFile.getStorageType().equals(StorageTypeEnum.LOCAL.getCode())){
                deleteLocal(sysFile.getDeleteUrl(),sysFile.getFileId());
            }
            if (sysFile.getStorageType().equals(StorageTypeEnum.QINIU.getCode())){
                deleteQiniu(sysFile.getDeleteUrl(),sysFile.getFileId());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
